package com.googlecode.vmock.matchers;

import com.googlecode.vmock.matchers.ranking.MatcherRanking;
import com.googlecode.vmock.utils.LogicOperator;
import com.googlecode.vmock.utils.Validate;

/**
 * Matches all values that satisfy a given logical operator for a given value.
 * 
 * @author marcin.jagus
 * @param <T> Type of a given value. Must implement the {@link Comparable} interface
 */
public class CompareMatcher<T extends Comparable<T>> extends AbstractMatcher {

    static {
        MatcherRanking.setRanking(CompareMatcher.class, MatcherRanking.COMPARE_MATCHER_DEFAULT_RANKING);
    }

    private LogicOperator operator;
    private T value;

    /**
     * Creates a new matcher which matches all values that satisfy a given logical operator for a given value.
     * 
     * @param operator Given logical operator. Cannot be <code>null</code>.
     * @param value Given value. Cannot be <code>null</code>.
     */
    public CompareMatcher(LogicOperator operator, T value) {
        Validate.notNull(operator, "operator == null");
        Validate.notNull(value, "value == null");

        this.value = value;
        this.operator = operator;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean matches(Object value) {
        if (this.value.getClass().isAssignableFrom(value.getClass())) {
            T theirValue = (T) value;
            return operator.operate(theirValue, this.value);
        } else {
            throw new IllegalArgumentException("Given value is not a (sub)class of " + value.getClass());
        }
    }

    @Override
    public String toString() {
        return String.format("CompareMatcher(%s, %s)", operator, value);
    }
}
